#include "functions.h"
#include <bitset>
using namespace std;
unsigned char Code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ,.!?;";
int qMatrix [] = {16,11,10,16,24,40,51,61,
				12,12,14,19,26,58,60,55,
				14,13,16,24,40,57,69,56,
				14,17,22,29,51,87,80,64,
				18,22,37,56,68,109,103,77,
				24,35,55,64,81,104,113,92,
				49,64,78,87,103,121,120,101,
				72,92,95,98,112,100,103,99};
int blockSize = 8;
float threshold = 30;
float compressionScale = 3;
int charsPerBlock = 1;
int nBitsCode = 5;
bool compressionJPG = false;
float sigmaNoise = 0.;
int quality = 100;
string xorMask;

/*
Levanta los parametros de configuracion presentes en config.txt
*/
void loadConfig(){
	ifstream archi;
	archi.open("config.txt");
	string str_line;
	char* line;
	if(archi.is_open()){

		getline(archi,str_line);
		getline(archi,str_line);
		getline(archi,str_line);
		line = &str_line[0];
		blockSize = atoi(line);

		getline(archi,str_line);
		getline(archi,str_line);
		line = &str_line[0];
		threshold = atof(line);

		getline(archi,str_line);
		getline(archi,str_line);
		line = &str_line[0];
		compressionScale = atoi(line);

		getline(archi,str_line);
		getline(archi,str_line);
		line = &str_line[0];
		charsPerBlock = atoi(line);

		getline(archi,str_line);
		getline(archi,str_line);
		line = &str_line[0];
		nBitsCode = atoi(line);

		getline(archi,str_line);
		getline(archi,str_line);
		line = &str_line[0];
		compressionJPG = atoi(line);

		getline(archi,str_line);
		getline(archi,str_line);
		line = &str_line[0];
		sigmaNoise = atof(line);

		getline(archi,str_line);
		getline(archi,str_line);
		line = &str_line[0];
		quality = atof(line);

		getline(archi,str_line);
		getline(archi,str_line);
		xorMask = str_line;

		archi.close();
	}
}

/**
Levanta el archivo de texto a esteganografiar... ojo, esta funcion solo levanta la primer linea
*/
char* loadText(const char* path){
	ifstream archi;
	archi.open(path);
	string str_line;
	char* text;
	if(archi.is_open()){
		getline(archi,str_line);
		str_line+='\0';
		text = &str_line[0];
		archi.close();
	}
	return text;
}

/**
Dado un entero "val", convierte a binario y lo devuelve en "bin"
Atencion: bin debe estar alocada su memoria
*/
void toBinary(bool* bin, int val, int size){
	for (int i=0; (i<size && val!=0); i++){
		bin[size-1-i] = val % 2;
		val = int(val/2);
	}
	return;
}

/**
devuelve el valor entero que representa la cadena actual
*/
int toInt(bool* bin, int size){
	int aux = 0;
	for(int i=0;i<size;i++){
		if(bin[i])
			aux += pow(2.0,(size-1)-i);
	}
	return aux;
}


/**
Dado un caracter encuentra el indice dentro del codigo (lo que sería su numero ASCII)
*/
int findIndex(char c){
	int i=0;
	while(Code[i]!=c) i++;
	return i;
}

/**
Mete los charsPerBlock caracteres dentro de los primeros elementos del arreglo vZig
*/
void LSB(vector<float>& vZig,char* pChar, int p){
	for(int i=0;i<charsPerBlock;i++){
		bool insert[] = {0,0,0,0,0};
		toBinary(insert,findIndex(pChar[p]), nBitsCode); //convierto a binario el indice del caracter, ejp: "A" tiene indice "0" => 00000, "I" tiene indice "8" => 01000
		//cout<<"metiendo: "<<pChar[p]<<"   - cuyo indice es: "<<findIndex(pChar[p])<<endl;
		for(int j=1;j<=nBitsCode;j++){
			bool auxBin[] = {0,0,0,0,0,0,0,0};
			int sign = 1; //me guardo e signo, y trabajo el numero como binario positivo
			int val = round(vZig[i*nBitsCode+j]);
			if(val<0) sign = -1;
			toBinary(auxBin, val, 8); //convierto a binario el valor del pixel, ejp 127 => 01111111
			auxBin[7] = insert[j-1]; //meto la posicion j del codigo "ascci" del caracter a insertar en la ultima posicion del pixel actual
			//cout<<" entra: "<<vZig[i*nBitsCode+j]<<"   sale: "<<sign*toInt(auxBin,8) /*+ decimals*/<< endl;
			vZig[i*nBitsCode+j] = sign*toInt(auxBin,8);
		}
		p += 1;
	}

}

void LSBInv(vector<float>& vZig, vector<char>& pChar){
	for(int i=0;i<charsPerBlock;i++){
		//cout<<"detectando valor..."<<endl;
		bool insert[] = {0,0,0,0,0};
		for(int j=1;j<=nBitsCode;j++){
			bool auxBin[] = {0,0,0,0,0,0,0,0};
			int val = round(vZig[i*nBitsCode+j]);
			toBinary(auxBin, val, 8); //convierto a binario el valor del pixel, ejp 127 => 01111111
			insert[j-1] = auxBin[7]; //tomo el ultimo bit del pixel
			//cout<<" entra: "<<vZig[i*nBitsCode+j]<<"   detecta: "<<int(auxBin[7])<< endl;
		}
		int index = toInt(insert,nBitsCode);
		pChar.push_back(Code[index]);
	}
}

bool th(float val){
	return (val > threshold);
}

void makeBase(CImgList<>& bases){
	for(int u=0;u<blockSize;u++){
		for(int v=0;v<blockSize;v++){
			CImg<float> sBase(blockSize,blockSize);
			cimg_forXY(sBase,x,y)	sBase(x,y) = cos((((2*x)+1)*u*pi)/(2*blockSize)) * cos((((2*y)+1)*v*pi)/(2*blockSize));
			bases[u*blockSize+v] = sBase;
		}
	}
}

bool blockMultiple (CImg<float>& img){
	unsigned int w = img.width(), h = img.height();
	if((!(w%blockSize)) && (!(h%blockSize))) return true;
	return false;
}

void zigZag(CImg<float>& dctBlock,vector<float>& vZig,bool inverse){
	int i = 0, j = 0, dir = 1; //dir 1=hacia arriba-derecha 0=abajo-izquierda
	bool notBord = true;
	int maxim = blockSize-1;
	int index = 0;
	do{
		//cout<<"i: "<<i<<"  - j: "<<j<<endl;
		if(!inverse)
			vZig[index] = dctBlock(i,j);
		else
			dctBlock(i,j) = vZig[index];
		if((j==0 || j==maxim) && notBord){
			if(i!=maxim) i++;
			else j++;
			if(j==0) dir = 1;
			else dir = 0;
			notBord = false;
		}else{
			if((i==0 || i==maxim) && notBord){
				if(j!=maxim)j++;
				else i++;
				if(i==0) dir = 0;
				else dir = 1;
				notBord = false;
			}else{
				if(dir==0){ //en diagonal hacia abajo
					i++; j--; notBord = true;
				}else{ //en diagonal hacia arriba
					i--; j++; notBord = true;
				}
			}
		}
		index++;
	}while(i!=maxim || j!=maxim);
	if(!inverse)
		vZig[index] = dctBlock(i,j);
	else
		dctBlock(i,j) = vZig[index];
}

void encriptyon(char* pChar){
  cout<<endl<<"Cadena antes de encriptar:"<<&pChar[0]<<endl;
  bitset<5>mask(string("10101"));
  bitset<5>cad; cad.reset();
  int i,j,index;
  bool code[] = {0,0,0,0,0};
  for(i=0;pChar[i]!='\0';i++){
    cad.reset();
    toBinary(code,findIndex(pChar[i]),nBitsCode);
    for(j=0;j<nBitsCode;j++)
      if(code[j]) cad.set(j);
    cad=cad^mask; //xor
    for(j=0;j<nBitsCode;j++){
      if(cad.test(j)) code[j]=1;
      else code[j]=0;
    }
    index = toInt(code,nBitsCode);
    cout<<index<<", ";
		pChar[i]=Code[index];
  }
  cout<<endl<<endl<<"Cadena despues de encriptar:"<<&pChar[0];
}


